package abc.base;

import abc.enums.ActionType;
import abc.model.IEntity;
import abc.model.ResponseData;
import abc.model.PageInfo;
import com.baomidou.mybatisplus.core.metadata.IPage;

import java.io.Serializable;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutionException;

public interface IBll<T extends BaseModel, V extends IEntity<?>> extends IBaseResponse {
    default boolean isReturnNullableAtBefore(ActionType actionType) {
        switch (actionType) {
            case COUNT:
            case SUM:
            case AVG:
            case MAX:
            case MIN:
            case INSERT:
            case UPDATE:
            case DELETE:
            case BATCH_DELETE:
            case UPLOAD:
            case DOWNLOAD:
            case PLAY_VIDEO:
            case EXPORT:
            case IMPORT:
                return true;
        }
        return false;
    }

    default Optional<ResponseData> get(T data, ActionType actionType) {
        ResponseData<V> result = this.call(data, actionType);
        if(result == null) {
             if(isReturnNullableAtBefore (actionType)) {
                return Optional.ofNullable(null);
            }
            return Optional.ofNullable(success(data));
        }
        return Optional.ofNullable(result);
    }

    default Optional<ResponseData> list(T data, ActionType actionType) {
        ResponseData result = this.call(data, actionType);
        if(result == null) {
            if(isReturnNullableAtBefore (actionType)) {
                return Optional.ofNullable(null);
            }
            return Optional.ofNullable(success(data));
        }
        return Optional.ofNullable(result);
    }

    default Optional<ResponseData> list(List<T> data, ActionType actionType) {
        ResponseData result = this.call(data, actionType);
        if(result == null) {
            if(isReturnNullableAtBefore (actionType)) {
                return Optional.ofNullable(null);
            }
            return Optional.ofNullable(success(data));
        }
        return Optional.ofNullable(result);
    }

    default Optional<ResponseData> list(IPage iPage, ActionType actionType) {
        ResponseData result = this.call(iPage.getRecords(), actionType);
        if(result == null) {
            if(isReturnNullableAtBefore (actionType)) {
                return Optional.ofNullable(null);
            }
            result = success(iPage.getRecords());
        }
        result.setPageInfo(new PageInfo() {{
            setPageIndex(iPage.getPages());
            setPageSize(iPage.getSize());
            setTotalRecords(iPage.getTotal());
        }});
        return Optional.ofNullable(result);
    }

    default Optional<ResponseData<Serializable>> exec(T data, ActionType actionType) {
        ResponseData<Serializable> result = this.call(data, actionType);
        if(result == null) {
            if(isReturnNullableAtBefore (actionType)) {
                return Optional.ofNullable(null);
            }
            return Optional.ofNullable(success(data));
        }
        return Optional.ofNullable(result);
    }

    default Optional<ResponseData> execBatch(List<T> data, ActionType actionType) {
        ResponseData<List<Serializable>> result = this.call(data, actionType);
        if(result == null) {
            if(isReturnNullableAtBefore (actionType)) {
                return Optional.ofNullable(null);
            }
            return Optional.ofNullable(success(data));
        }
        return Optional.ofNullable(result);
    }

    default <S, R> ResponseData<R> call(S data, ActionType actionType) {
        return null;
    }

    default <S, R, T> ResponseData<R> call(S data, ActionType actionType, T type) {
        return null;
    }

    default <S, R, T1, T2> ResponseData<R> call(S data, ActionType actionType, T1 type1, T2 type2) {
        return null;
    }

    default <S, R, T1, T2, T3> ResponseData<R> call(S data, ActionType actionType, T1 type1, T2 type2, T3 type3) {
        return null;
    }

    default <S, R, T1, T2, T3, T4> ResponseData<R> call(S data, ActionType actionType, T1 type1, T2 type2, T3 type3, T4 type4) {
        return null;
    }

    default <S, R, T1, T2, T3, T4, T5> ResponseData<R> call(S data, ActionType actionType, T1 type1, T2 type2, T3 type3, T4 type4, T5 type5) {
        return null;
    }
}
